﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Xfs
{
    [XfsObjectSystem]
    public class XfsSessionAwakeSystem : XfsAwakeSystem<XfsSession>
    {
        public override void Awake(XfsSession self)
        {
            self.requestCallback.Clear();
        }
    }



    public static class XfsSessionHelper
    {
		#region ReceiveAsync-进 OnRead XfsRun-再进///接收包裹信息
		public static void ReceiveAsync(this XfsSession self, Socket socket)
		{
			self.Init();

			self.GetComponent<XfsAsyncUserToken>().Init(socket);
			self.IsRunning = true;

			///Client，如果服户端有消息包投递过来，则开始接收消息包
			if (!socket.ReceiveAsync(self.GetComponent<XfsAsyncUserToken>().ReceiveEventArgs))//投递接收请求
			{
				self.GetComponent<XfsAsyncUserToken>().ProcessReceive(self.GetComponent<XfsAsyncUserToken>().ReceiveEventArgs);
			}
		}

		public static void OnRead(this XfsSession self, object obj, object message)
		{
			try
			{
				self.XfsRun(obj, message);
			}
			catch (Exception e)
			{
				Console.WriteLine(XfsTimeHelper.CurrentTime() + e);
			}
		}

		public static void XfsRun(this XfsSession self, object obj, object message)
		{
			///确认本消息是不是response消息
			IXfsResponse? response = message as IXfsResponse;

			if (response == null)
			{
				if (message != null)
				{
					///拿到本消息的操作码
					ushort opcode = XfsGame.XfsSence.GetComponent<XfsOpcodeTypeComponent>().GetOpcode(message.GetType());

					//Console.WriteLine(XfsTimeHelper.CurrentTime() + " " + this.GetType() + " 118. opcode: " + opcode);
					//Console.WriteLine(XfsTimeHelper.CurrentTime() + " " + this.GetType() + " 119. message: " + message);

					///将消息发送进消息分流中心
					if (self.NetSocket != null)
					{
						self.NetSocket.MessageDispatcher?.Dispatch(self, opcode, message);
					}
				}
				return;
			}
			else
			{
				Action<IXfsResponse>? action;
				if (self.requestCallback.TryGetValue(response.RpcId, out action))
				{
					self.requestCallback.Remove(response.RpcId);
					action(response);
					//Console.WriteLine(XfsTimeHelper.CurrentTime() + " " + this.GetType() + " 135. message: " + message);
				}
				else
				{
					Console.WriteLine(XfsTimeHelper.CurrentTime() + " " + self.GetType() + " 138. message: " + $"not found rpc, response message: {response}");
				}
			}
		}
		#endregion

		#region Call Send /// 外网发送消息		
		private static int RpcId { get; set; }

		public static XfsTask<IXfsResponse> Call(this XfsSession self, IXfsRequest request, CancellationToken cancellationToken)
		{
			int rpcId = ++RpcId;
			var tcs = new XfsTaskCompletionSource<IXfsResponse>();

			self.requestCallback[rpcId] = (response) =>
			{
				try
				{
					if (XfsErrorCode.IsRpcNeedThrowException(response.Error))
					{
						Console.WriteLine(XfsTimeHelper.CurrentTime() + " : " + response.Message);
					}

					tcs.SetResult(response);
				}
				catch (Exception e)
				{
					tcs.SetException(new Exception($"Rpc Error: {request.GetType().FullName}", e));
				}
			};

			cancellationToken.Register(() => self.requestCallback.Remove(rpcId));

			request.RpcId = rpcId;
			self.Send(request);
			return tcs.Task;
		}

		public static XfsTask<IXfsResponse> Call(this XfsSession self, IXfsRequest request)
		{
			int rpcId = ++RpcId;
			var tcs = new XfsTaskCompletionSource<IXfsResponse>();

			self.requestCallback[rpcId] = (response) =>
			{
				try
				{
					if (XfsErrorCode.IsRpcNeedThrowException(response.Error))
					{
						Console.WriteLine(XfsTimeHelper.CurrentTime() + " : " + response.Message);
					}

					tcs.SetResult(response);
				}
				catch (Exception e)
				{
					tcs.SetException(new Exception($"Rpc Error: {request.GetType().FullName}", e));
				}
			};

			request.RpcId = rpcId;
			self.Send(request);
			return tcs.Task;
		}

		public static void Reply(this XfsSession self, IXfsResponse message)
		{
			if (!self.IsOuter)
			{
				self.SendInner(message);
				return;
			}
			self.Send(message);
		}

		public static void Send(this XfsSession self, IXfsMessage message)
		{
			if (self.IsClosed)
			{
				Console.WriteLine(XfsTimeHelper.CurrentTime() + " 216. " + self.GetType().Name + " InstanceId: " + self.InstanceId + " 已经被Closed了");

				self.Close();

				return;
			}

			if (self.UserToken != null && self.UserToken.Socket != null)
			{
				self.UserToken.Send(message);
			}
		}
		#endregion

		#region Call Send Inner /// 内网发送消息	
		public static XfsTask<IXfsResponse> CallInner(this XfsSession self, IXfsRequest request, CancellationToken cancellationToken)
		{
			int rpcId = ++RpcId;
			var tcs = new XfsTaskCompletionSource<IXfsResponse>();

			self.requestCallback[rpcId] = (response) =>
			{
				try
				{
					if (XfsErrorCode.IsRpcNeedThrowException(response.Error))
					{
						Console.WriteLine(XfsTimeHelper.CurrentTime() + " : " + response.Message);
					}

					tcs.SetResult(response);
				}
				catch (Exception e)
				{
					tcs.SetException(new Exception($"Rpc Error: {request.GetType().FullName}", e));
				}
			};

			cancellationToken.Register(() => self.requestCallback.Remove(rpcId));

			request.RpcId = rpcId;
			self.SendInner(request);
			return tcs.Task;
		}

		public static XfsTask<IXfsResponse> CallInner(this XfsSession self, IXfsRequest request)
		{
			int rpcId = ++RpcId;
			var tcs = new XfsTaskCompletionSource<IXfsResponse>();

			self.requestCallback[rpcId] = (response) =>
			{
				try
				{
					if (XfsErrorCode.IsRpcNeedThrowException(response.Error))
					{
						Console.WriteLine(XfsTimeHelper.CurrentTime() + " : " + response.Message);
					}

					tcs.SetResult(response);
				}
				catch (Exception e)
				{
					tcs.SetException(new Exception($"Rpc Error: {request.GetType().FullName}", e));
				}
			};

			request.RpcId = rpcId;
			self.SendInner(request);
			return tcs.Task;
		}

		public static void ReplyInner(this XfsSession self, IXfsResponse message)
		{
			if (self.IsDisposed)
			{
				throw new Exception("session已经被Dispose了");
			}

			self.SendInner(message);
		}

		public static void SendInner(this XfsSession self, IXfsMessage message)
		{
			self.XfsRun(self, message);
		}
		#endregion

		#region Init Close		
		public static void Init(this XfsSession self)
		{
			self.IsClosed = false;
			if (!self.IsOuter)
			{
				self.IsRunning = true;
			}

			///添加心跳包
			if (self.GetComponent<XfsHeartComponent>() == null)
			{
				self.AddComponent<XfsHeartComponent>();
			}
			self.GetComponent<XfsHeartComponent>().Init();

			if (self.GetComponent<XfsAsyncUserToken>() == null)
			{
				self.AddComponent<XfsAsyncUserToken>();
			}
		}

		public static void Close(this XfsSession self)
		{
			if (self.IsClosed)
			{
				return;
			}

			if (self.GetComponent<XfsHeartComponent>() != null)
			{
				self.GetComponent<XfsHeartComponent>().Close();
			}
			if (self.GetComponent<XfsAsyncUserToken>() != null)
			{
				self.GetComponent<XfsAsyncUserToken>().Close();
			}

			foreach (Action<IXfsResponse> action in self.requestCallback.Values.ToArray())
			{
				action.Invoke(new XfsResponseMessage());
			}
			self.requestCallback.Clear();

			if (self.NetSocket != null)
			{
				///从会话列表中移除
				self.NetSocket.Remove(self);
			}

			self.IsClosed = true;
			self.IsRunning = false;
		}		
		#endregion







		public static async XfsTask UserLogin(this XfsSession self, string username, string password)
        {
            if (!self.IsRunning) return;
            await self.Call(new C4S_User() { Username = username, Password = password });
        }

        public static async XfsVoid UserLogCall<S4C_User>(this XfsSession self, string username, string password, S4C_User s4c) 
        {
            if (self.IsRunning)
            {
                s4c = (S4C_User)await self.Call(new C4S_User() { Username = username, Password = password });                
            }
        }

        //public static async XfsTask<S4C_User> AsyncUserLogin(this XfsSession self, string username, string password)
        //{
        //    XfsTaskCompletionSource<S4C_User> tcs = new XfsTaskCompletionSource<S4C_User>();
        //    S4C_User s4c = (S4C_User)await self.Call(new C4S_User() { Username = username, Password = password });
        //    if (s4c != null)
        //    {
        //        tcs.SetResult(s4c);
        //        return tcs.Task;
        //    }
        //    Console.WriteLine(XfsTimeHelper.CurrentTime() + " " + self.GetType().Name + " 20. User." + username + " 开始登录...");
        //    return tcs.Task;
        //}


    }
}
